refactor git-autograder to generalize bebavior and reduce indirections#21
refactor git-autograder to generalize bebavior and reduce indirections#21SAN-MUYUN wants to merge 7 commits intogit-mastery:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Refactors git-autograder to expose tag-related functionality through the repo abstraction and adds small utilities for working with commits and underlying GitPython objects.
Changes:
- Introduces
GitAutograderTagandTagHelperto query local/remote tags and resolve tag→commit. - Extends the repo abstraction (
GitAutograderRepoBase,GitAutograderRepo,NullGitAutograderRepo) with atagshelper. - Adds convenience accessors:
GitAutograderCommit.message,CommitHelper.commit_from_message, andGitAutograderExercise.git_repo.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/git_autograder/tag.py | Adds a wrapper type for GitPython tag refs with convenience properties. |
| src/git_autograder/helpers/tag_helper.py | Adds tag querying utilities (local tags, remote tag names, tag→commit helpers). |
| src/git_autograder/repo/repo_base.py | Adds tags to the repo interface. |
| src/git_autograder/repo/repo.py | Wires TagHelper into the concrete repo implementation. |
| src/git_autograder/repo/null_repo.py | Adds tags property to the null repo (currently with an incorrect error message). |
| src/git_autograder/helpers/commit_helper.py | Adds helper to find a commit by message. |
| src/git_autograder/commit.py | Adds decoded message accessor for commits. |
| src/git_autograder/exercise.py | Adds git_repo property for accessing the underlying Repo when not ignored. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/git_autograder/repo/null_repo.py
Outdated
| @property | ||
| def tags(self) -> TagHelper: | ||
| raise AttributeError( | ||
| "Cannot access attribute files on NullGitAutograderRepo. Check that your repo_type is not 'ignore'." |
There was a problem hiding this comment.
The AttributeError message in tags is copy/pasted from files (it says "Cannot access attribute files"), which will mislead users. Update it to reference tags (and consider matching the ignore/local-ignore wording used elsewhere, e.g. GitAutograderExercise.git_repo).
| "Cannot access attribute files on NullGitAutograderRepo. Check that your repo_type is not 'ignore'." | |
| "Cannot access attribute tags on NullGitAutograderRepo. Check that your repo_type is not 'ignore'." |
src/git_autograder/repo/null_repo.py
Outdated
| @property | ||
| def tags(self) -> TagHelper: | ||
| raise AttributeError( | ||
| "Cannot access attribute files on NullGitAutograderRepo. Check that your repo_type is not 'ignore'." |
There was a problem hiding this comment.
It should be tags instead of files in the error message.
| names: List[str] = [] | ||
| seen = set() | ||
|
|
||
| for line in raw.splitlines(): | ||
| parts = line.split() | ||
| if len(parts) != 2: | ||
| continue | ||
|
|
||
| ref = parts[1] | ||
| if not ref.startswith("refs/tags/"): | ||
| continue | ||
|
|
||
| name = ref[len("refs/tags/") :] | ||
| if name.endswith("^{}"): | ||
| name = name[:-3] | ||
|
|
||
| if name not in seen: | ||
| seen.add(name) | ||
| names.append(name) | ||
|
|
||
| return names |
There was a problem hiding this comment.
Is there any reason that we need both names and seen for this method? Is it for maintaining the order?
Actually, we don't need the names list; we can add valid names to seen, and convert the seen set to a list as the return value.
| contents = [ | ||
| line.strip() for line in input_file.readlines() if line.strip() != "" | ||
| ] | ||
| if contents != expected: |
There was a problem hiding this comment.
You are comparing a list[str] against str, which will always return False.
| def points_to(self, tag_name: str, commit: GitAutograderCommit) -> bool: | ||
| tag_commit = self.commit_or_none(tag_name) | ||
| return tag_commit is not None and tag_commit.hexsha == commit.hexsha |
There was a problem hiding this comment.
This method looks like a behaviour of GitAutograderTag instead of TagHelper to me.
| def commit_or_none(self, tag_name: str) -> Optional[GitAutograderCommit]: | ||
| t = self.tag_or_none(tag_name) | ||
| if t is None: | ||
| return None | ||
| return t.commit |
There was a problem hiding this comment.
Why do we need this method? We will check whether the tag exists before retrieving its commit in our verify logic.
|
@desmondwong1215 Really appreciate the feedbacks! I have updated the PR accordingly, feel free to test it out and review again. |
desmondwong1215
left a comment
There was a problem hiding this comment.
Leave some comments. Everything else LGTM!
| with ( | ||
| open(given, "r") as given_file, | ||
| open(expected, "r") as expected_file, | ||
| ): |
There was a problem hiding this comment.
Is there any reason that we are not using file() or file_or_none() here?
| contents = given_file.read().replace("\n", "") | ||
| expected_contents = expected_file.read().replace("\n", "") | ||
| return contents == expected_contents |
There was a problem hiding this comment.
In the current implementation, a\nbc and ab\nc will be equal, but their content should be different. Is this the intended implementation?
There was a problem hiding this comment.
This is done intentionally, since we do not want to punish users because of variation in line breaks. As long as the actual content is the same, we are good with it.
Anyways, for easy future integration, I will add a boolean field for developers to decide whether they want exact content or not.
| if name not in names: | ||
| names.append(name) |
There was a problem hiding this comment.
Is the ordering of the tag important in this case, as using set will be more efficient?
There was a problem hiding this comment.
Personally I find using of set is unnecessary, just like you pointed out in the previous review. For a single exercise, it is unlikely that we have large number of tags such that we will need to use a set to keep track of the tags. It would be good to keep the ordering in some cases.
|
@desmondwong1215 fixed the |
Fixes #5 , fixes #6 , fixes #8
refactor code to generalize behavior and reduce indirections
RFC: